#pragma once

namespace Khaos
{
    //////////////////////////////////////////////////////////////////////////
    template<typename T>
    struct TIntVector2
    {
        TIntVector2() : x(0), y(0) {}
        explicit TIntVector2( T s ) : x(s), y(s) {}
        TIntVector2( T x1, T y1 ) : x(x1), y(y1) {}

        static const TIntVector2& zero()
        {
            static const TIntVector2 s_val( 0, 0 );
            return s_val;
        }

        const T* ptr() const
        {
            return &x;
        }

        T* ptr()
        {
            return &x;
        }

        const T& operator[]( size_t i ) const
        {
            khaosAssert( i < 2 );
            return (&x)[i];
        }

        T& operator[]( size_t i )
        {
            khaosAssert( i < 2 );
            return (&x)[i];
        }

        bool operator==( const TIntVector2& rhs ) const
        {
            return this->x == rhs.x && this->y == rhs.y;
        }

        bool operator!=( const TIntVector2& rhs ) const
        {
            return ! this->operator==(rhs);
        }

        TIntVector2 operator+( const TIntVector2& rhs ) const
        {
            return TIntVector2( x + rhs.x, y + rhs.y );
        }

        TIntVector2& operator+=( const TIntVector2& rhs )
        {
            x += rhs.x;
            y += rhs.y;
            return *this;
        }

        TIntVector2 operator/(const TIntVector2& rhs) const
        {
            return TIntVector2(x / rhs.x, y / rhs.y);
        }

        TIntVector2& operator/=(const TIntVector2& rhs)
        {
            x /= rhs.x;
            y /= rhs.y;
            return *this;
        }

        T x;
        T y;
    };

    typedef TIntVector2<int>  IntVector2;

    //////////////////////////////////////////////////////////////////////////
    struct IntRect
    {
    public:
        IntRect() : left(0), top(0), right(0), bottom(0) {}
        IntRect( int l, int t, int r, int b ) : left(l), top(t), right(r), bottom(b) {}
        IntRect( const IntVector2& lt, const IntVector2& rb ) : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) {}

    public:
        bool operator==( const IntRect& rhs ) const
        {
            //return this->left == rhs.left && this->top == rhs.top &&
            //       this->right == rhs.right && this->bottom == rhs.bottom;

            khaosStaticAssert( sizeof(long long) == sizeof(int) * 2 );

            return *(long long*)(&left) == *(long long*)(&rhs.left) &&
                   *(long long*)(&right) == *(long long*)(&rhs.right);
        }

        bool operator!=( const IntRect& rhs ) const
        {
            return !(this->operator==(rhs));
        }

    public:
        void setRect( int l, int t, int r, int b )
        {
            left   = l;
            top    = t;
            right  = r;
            bottom = b;
        }

        void setRect( const IntVector2& lt, const IntVector2& rb )
        {
            setRect( lt.x, lt.y, rb.x, rb.y );
        }

        void makeRect( int l, int t, int w, int h )
        {
            left   = l;
            top    = t;
            right  = l + w;
            bottom = t + h;
        }

        void makeRect( const IntVector2& lt, const IntVector2& sz )
        {
            makeRect( lt.x, lt.y, sz.x, sz.y );
        }

        void checkCorner()
        {
            if ( left > right )
                std::swap( left, right );

            if ( top > bottom )
                std::swap( top, bottom );
        }

		void setEmpty()
		{
			left   = INT_MAX;
			top    = INT_MAX;
			right  = INT_MIN;
			bottom = INT_MIN;
		}

        bool isEmpty() const
        {
            return right <= left || bottom <= top;
        }

		void merge( const IntRect& rhs )
		{
			if ( rhs.left < left )
				left = rhs.left;

			if ( rhs.top < top )
				top = rhs.top;

			if ( rhs.right > right )
				right = rhs.right;

			if ( rhs.bottom > bottom )
				bottom = rhs.bottom;
		}

		void intersect( const IntRect& rhs )
		{
			if ( rhs.left > left )
				left = rhs.left;

			if ( rhs.top > top )
				top = rhs.top;

			if ( rhs.right < right )
				right = rhs.right;

			if ( rhs.bottom < bottom )
				bottom = rhs.bottom;
		}

        int getWidth()  const { return right - left; }
        int getHeight() const { return bottom - top; }

        IntVector2 getCenter() const
        {
            return IntVector2( (left + right) / 2, (top + bottom) / 2 ); 
        }

        const IntVector2& getLeftTop() const
        {
            return *(IntVector2*)(&left);
        }

        IntVector2& getLeftTop()
        {
            return *(IntVector2*)(&left);
        }

        const IntVector2& getRightBottom() const
        {
            return *(IntVector2*)(&right);
        }

        IntVector2& getRightBottom()
        {
            return *(IntVector2*)(&right);
        }

        int*       ptr()       { return &left; }
        const int* ptr() const { return &left; }

    public:
        int left;
        int top;
        int right;
        int bottom;
    };

    //////////////////////////////////////////////////////////////////////////
  
}

